home *** CD-ROM | disk | FTP | other *** search
/ Delphi Magazine Collection 2001 / Delphi Magazine Collection 20001 (2001).iso / DISKS / ISSUE12 / SYSTEM / HELPINFO.PAS next >
Encoding:
Pascal/Delphi Source File  |  1996-07-27  |  9.7 KB  |  310 lines

  1. unit HelpInfo;
  2.  
  3. interface
  4.  
  5. uses WinTypes, WinProcs, SysUtils;
  6.  
  7. const
  8.     HBadOpen = 1000;           { Can't open the help file   }
  9.     HIOError = 1001;           { I/O Error reading the file }
  10.     HBadSig  = 1002;           { Not a Windows Help file    }
  11.     HNoSys   = 1003;           { |SYSTEM file is missing !  }
  12.  
  13. function  OpenHelpFile (fileName: PChar; var hFile: Pointer): Integer;
  14. procedure CloseHelpFile (hFile: Pointer);
  15.  
  16. implementation
  17.  
  18. type
  19.     { Header for entire .HLP file }
  20.     THFileHeader = record
  21.                       MagicNumber: LongInt;
  22.                       WHIFSOffset: LongInt;
  23.                       Negative: LongInt;
  24.                       FileSize: LongInt;
  25.                   end;
  26.  
  27.     { Header for each internal WHIFS file }
  28.     TFileHeader = record
  29.                       FilePlusHdr: LongInt;    { size with header }
  30.                       FileSize:    LongInt;    { size without header }
  31.                       NullByte:    Byte;       { always zero... }
  32.                   end;
  33.  
  34.     TWHIFSHeader = record
  35.                       Magic: array [0..17] of Byte;
  36.                       Junk: array [0..12] of Byte;
  37.                       Zero, NSplits, RootPage, MinusOne: Integer;
  38.                       TotPages, NLevels: Integer;
  39.                       TotalWHIFSEntries: LongInt;
  40.                    end;
  41.  
  42.     PSysHeader = ^TSysHeader;
  43.     TSysHeader = record
  44.                      Magic, Version, Revision, Zero: Byte;
  45.                      AlwaysOne: Word;
  46.                      GenDate: LongInt;
  47.                      Flags: Word;
  48.                  end;
  49.  
  50.     PHelpHandle = ^THelpHandle;
  51.     THelpHandle = record
  52.                       _fd: Integer;                       { handle of open help file     }
  53.                       _fn: String;                        { full pathname of the file    }
  54.                       _scratch1: array [0..255] of Char;  { scratch buffer               }
  55.                       _WHIFSStart: LongInt;               { start of file system         }
  56.                       _FirstLeaf: Integer;                { first leaf node number       }
  57.                       _Title: array [0..255] of Char;     { help system title            }
  58.                       _Copyright: array [0..255] of Char; { help system copyright        }
  59.                       _MacroCount: Integer;               { number of startup macros     }
  60.                       _MacroData: PChar;                  { pointer to macro data        }
  61.                       _MacroDataSize: Word;               { size of _MacroData pointer   }
  62.                       _FileCount: Integer;                { # of files in help system    }
  63.                       _System: PSysHeader;                { pointer to in-memory |SYSTEM }
  64.                       _FileDirectory: Pointer;            { pointer to file directory    }
  65.                  end;
  66.  
  67. procedure GotoWHIFSPage (p: PHelpHandle; pageNum: LongInt);
  68. begin
  69.     with p^ do _llseek (_fd, _WHIFSStart + (pageNum * 1024), 0);
  70. end;
  71.  
  72. procedure ReadString (fd: Integer; dest: PChar);
  73. begin
  74.     while True do
  75.     begin
  76.         _lread (fd, dest, 1);
  77.         if dest^ = #0 then break;
  78.         Inc (dest);
  79.     end;
  80. end;
  81.  
  82. function FindWHIFSFile (p: PHelpHandle; fileName: PChar): LongInt;
  83. var
  84.     count: Integer;
  85.     fEntry: ^PChar;
  86. begin
  87.     FindWHIFSFile := -1;
  88.     with p^ do
  89.     begin
  90.         fEntry := _FileDirectory;
  91.         for count := 0 to _FileCount - 1 do
  92.         begin
  93.             if lstrcmp (fileName, fEntry^) = 0 then
  94.             begin
  95.                 FindWHIFSFile := PLongInt (fEntry^ + lstrlen (fEntry^) + 1)^;
  96.                 Exit;
  97.             end;
  98.             Inc (fEntry);
  99.         end;
  100.     end;
  101. end;
  102.  
  103. procedure ReadFileDirectory (p: PHelpHandle);
  104. type
  105.     Node = record
  106.                Sig, Entries, Prev, Next: Integer;
  107.            end;
  108. var
  109.     f: Integer;
  110.     fEntry: ^PChar;
  111.     WHIFSNode: Node;
  112.     fname: array [0..255] of Char;
  113.  
  114. begin
  115.     with p^ do
  116.     begin
  117.         { Allocate memory for directory structure }
  118.  
  119.         _FileDirectory := AllocMem (_FileCount * sizeof (PChar));
  120.         fEntry := _FileDirectory;
  121.  
  122.         { Second pass - read the file directory }
  123.  
  124.         GotoWHIFSPage (p, _FirstLeaf);
  125.         while True do
  126.         begin
  127.             _lread (_fd, @WHIFSNode, sizeof (WHIFSNode));
  128.             for f := 1 to WHIFSNode.Entries do
  129.             begin
  130.                 ReadString (_fd, fname);
  131.                 fEntry^ := AllocMem (lstrlen (fname) + 1 + sizeof (LongInt));
  132.                 lstrcpy (fEntry^, fname);
  133.                 _lread (_fd, fEntry^ + lstrlen (fName) + 1, sizeof (LongInt));
  134.                 Inc (fEntry);
  135.             end;
  136.  
  137.             if WHIFSNode.Next = -1 then break;
  138.             GotoWHIFSPage (p, WHIFSNode.Next);
  139.         end;
  140.     end;
  141. end;
  142.  
  143. function LoadSystem (p: PHelpHandle): Integer;
  144. const
  145.     hpj_Title     = 1;                { title string }
  146.     hpj_Copyright = 2;                { copyright string }
  147.     hpj_Contents  = 3;                { contents }
  148.     hpj_MacroData = 4;
  149.     hpj_IconData  = 5;
  150.     hpj_SecWindow = 6;
  151.     hpj_Citation  = 8;
  152. var
  153.     Data: array [0..1] of Word;
  154.     DataPtr: PChar;
  155.  
  156.     bytesRead: LongInt;
  157.     sysOffset: LongInt;
  158.     fhdr: TFileHeader;
  159.     szBuffer: array [0..255] of Char;
  160.  
  161.     procedure AddMacro (macro: PChar);
  162.     var
  163.         sz: Word;
  164.     begin
  165.         with p^ do
  166.         begin
  167.             sz := lstrlen (macro) + 1;
  168.             if _MacroData = Nil then _MacroData := AllocMem (sz)
  169.             else _MacroData := ReAllocMem (_MacroData, _MacroDataSize, _MacroDataSize + sz);
  170.             lstrcpy (_MacroData + _MacroDataSize, macro);
  171.             Inc (_MacroDataSize, sz);
  172.             Inc (_MacroCount);
  173.         end;
  174.     end;
  175.  
  176. begin
  177.     LoadSystem := 0;
  178.     with p^ do
  179.     begin
  180.         sysOffset := FindWHIFSFile (p, '|SYSTEM');
  181.         if sysOffset = -1 then LoadSystem := HNoSys else
  182.         begin
  183.             { Read file header for |SYSTEM file }
  184.  
  185.             _llseek (_fd, sysOffset, 0);
  186.             _lread (_fd, @fhdr, sizeof (fhdr));
  187.             GetMem (_System, sizeof (TSysHeader));
  188.             _lread (_fd, PChar (_System), sizeof (TSysHeader));
  189.  
  190.             { Is it ancient ?  If so, title string only }
  191.             if _System^.Revision = $F then
  192.             begin
  193.                 _lread (_fd, _Title, 33);
  194.                 Exit;
  195.             end;
  196.  
  197.             { Now, grab any stuff that follows system header }
  198.             { It's organised as <Type><Size><Data>,,,<Type><Size><Data> }
  199.  
  200.             bytesRead := sizeof (TSysHeader);
  201.             while fhdr.FileSize > bytesRead do
  202.             begin
  203.                 _lread (_fd, @Data, sizeof (Data));
  204.                 GetMem (DataPtr, Data [1]);
  205.                 _lread (_fd, DataPtr, Data [1]);
  206.  
  207.                 { Now case out on the data type }
  208.                 case Data [0] of
  209.                     hpj_Title:      lstrcpy (_Title, DataPtr);
  210.                     hpj_Copyright:  if DataPtr^ <> #0 then lstrcpy (_Copyright, DataPtr)
  211.                                     else lstrcpy (_Copyright, 'None');
  212.                     hpj_MacroData:  AddMacro (DataPtr);
  213.                 end;
  214.  
  215.                 FreeMem (DataPtr, Data [1]);
  216.                 Inc (bytesRead, Data [1] + sizeof (Data));
  217.             end;
  218.         end;
  219.     end;
  220. end;
  221.  
  222. function OpenHelpFile (fileName: PChar; var hFile: Pointer): Integer;
  223. var
  224.     aPage: Word;
  225.     junk: LongInt;
  226.     hdr: THFileHeader;
  227.     whdr: TWHIFSHeader;
  228.     f, fd, ret: Integer;
  229.     p: PHelpHandle absolute hFile;
  230.  
  231. begin
  232.     ret := 0;
  233.     hFile := Nil;
  234.     fd := _lopen (fileName, 0);
  235.     if fd = -1 then ret := HBadOpen else
  236.     if _lread (fd, @hdr, sizeof (hdr)) <> sizeof (hdr) then ret := HIOError else
  237.     if hdr.MagicNumber <> $00035F3F then ret := HBadSig;
  238.  
  239.     if ret = 0 then
  240.     begin
  241.         CloseHelpFile (hFile);
  242.         p := AllocMem (sizeof (THelpHandle));
  243.         p^._fd := fd;
  244.         p^._fn := StrPas (fileName);
  245.         lstrcpy (p^._Title, 'None');
  246.         lstrcpy (p^._Copyright, 'None');
  247.         p^._WHIFSStart := hdr.WHIFSOffset + sizeof (whdr);
  248.  
  249.         { Read the WHIFS header }
  250.  
  251.         _llseek (fd, hdr.WHIFSOffset, 0);
  252.         _lread (fd, @whdr, sizeof (whdr));
  253.         p^._FileCount := whdr.TotalWHIFSEntries;
  254.  
  255.         { and find root page }
  256.  
  257.         f := 1;
  258.         aPage := 0;
  259.         GotoWHIFSPage (p, whdr.RootPage);
  260.         while f < whdr.NLevels do
  261.         begin
  262.             _lread (fd, @junk, sizeof (junk));
  263.             _lread (fd, @aPage, sizeof (aPage));
  264.             GotoWHIFSPage (p, aPage);
  265.             Inc (f);
  266.         end;
  267.  
  268.         p^._FirstLeaf := aPage;
  269.  
  270.         { Read directory and load the |SYSTEM file }
  271.  
  272.         ReadFileDirectory (p);
  273.         ret := LoadSystem (p);
  274.  
  275.     end
  276.     else if fd <> -1 then _lclose (fd);
  277.  
  278.     OpenHelpFile := ret;
  279. end;
  280.  
  281. procedure CloseHelpFile (hFile: Pointer);
  282. var
  283.     count: Integer;
  284.     fEntry: ^PChar;
  285.     p: PHelpHandle absolute hFile;
  286. begin
  287.     if hFile <> Nil then with p^ do
  288.     begin
  289.         _lclose (_fd);
  290.         if _System <> Nil then FreeMem (_System, sizeof (TSysHeader));
  291.         if _MacroDataSize <> 0 then FreeMem (_MacroData, _MacroDataSize);
  292.  
  293.         if _FileDirectory <> Nil then
  294.         begin
  295.             fEntry := _FileDirectory;
  296.             { First kill individual entries }
  297.             for count := 0 to _FileCount - 1 do
  298.             begin
  299.                 FreeMem (fEntry^, lstrlen (fEntry^) + 1 + sizeof (LongInt));
  300.                 Inc (fEntry);
  301.             end;
  302.             { Then kill directory itself }
  303.             FreeMem (_FileDirectory, _FileCount * sizeof (PChar));
  304.         end;
  305.         FreeMem (hFile, sizeof (THelpHandle));
  306.     end;
  307. end;
  308.  
  309. end.
  310.